package wiki.xsx.jg.core;

import java.io.File;
import java.io.PrintWriter;
import java.util.Map;

/**
 * Java文件生成器
 */
public class FileGenerator {

    /**
     * 生成Java文件
     * @param tableNames 表名，多个逗号分隔
     * @param driverClassName 数据库驱动名称
     * @param dbUrl 数据库地址
     * @param userName 数据库用户名
     * @param password 数据库密码
     * @param rootPath 包的根路径
     * @param packageName 完整包名，如com.xsx.test
     * @throws Exception
     */
    public static void run(
            String tableNames,
            String driverClassName,
            String dbUrl,
            String userName,
            String password,
            String rootPath,
            String packageName
    ) throws Exception{
        DatabaseService service = DatabaseAdapter.getServiceInstance(driverClassName, dbUrl, userName, password);
        Map<String, Map<String, Class<?>>> tableInfos = service.getTableInfo(tableNames);
        for (Map.Entry<String, Map<String, Class<?>>> tableInfo : tableInfos.entrySet()){
            write(rootPath, packageName, tableInfo.getKey(), tableInfo.getValue());
            System.out.println("[INFO] Create file: " + packageName + "." + tableInfo.getKey() + ".java");
        }
    }

    /**
     * 生成Java文件
     * @param rootPath 包的根路径
     * @param packageName 包名
     * @param className 类名
     * @param fieldAndType 属性及属性类型集合
     * @return 返回完整类字符串
     * @throws Exception
     */
    private static void write (
            String rootPath,
            String packageName,
            String className,
            Map<String, Class<?>> fieldAndType
    ) throws Exception{
        StringBuilder path = new StringBuilder(createPackage(rootPath, packageName));
        path.append(File.separator).append(titleCase(className)).append(".java");
        File file = new File(path.toString());
        if (!file.exists()){
            file.createNewFile();
        }
        PrintWriter writer = new PrintWriter(file);
        writer.write(classCase(packageName, className, fieldAndType));
        writer.close();
    }

    /**
     * 首字母大写
     * @param str 待转换的字符串
     * @return 返回首字母大写的字符串
     */
    private static String titleCase(String str) {
        if (str!=null&&str.trim().length()>0){
            char[] charArray = str.toCharArray();
            charArray[0] -= 32;
            return String.valueOf(charArray);
        }else{
            return str;
        }
    }

    /**
     * 创建包
     * @param filePath 文件路径(不包含包)
     * @param packageName 完整包名
     * @return 返回最终的完整路径
     */
    private static String createPackage(String filePath, String packageName){
        File dir = new File(filePath);
        if (!dir.exists()&&!dir.isDirectory()) {
            dir.mkdir();
        }
        StringBuilder pathBuilder = new StringBuilder(filePath);
        String pathes[] = packageName.split("\\.");
        for (String path : pathes){
            pathBuilder.append(File.separator).append(path);
            File file = new File(pathBuilder.toString());
            if (!file.exists()&&!file.isDirectory()) {
                file.mkdir();
            }
        }
        return pathBuilder.toString();
    }

    /**
     * 完整类字符串
     * @param packageName 包名
     * @param className 类名
     * @param fieldAndType 属性及属性类型集合
     * @return 返回完整类字符串
     */
    private static String classCase(String packageName, String className, Map<String, Class<?>> fieldAndType) {
        StringBuilder builder = new StringBuilder();
        builder.append(packageCase(packageName))
                .append("public class ").append(titleCase(className)).append(" {\n");
        for (Map.Entry<String, Class<?>> entry : fieldAndType.entrySet()){
            builder.append(fieldCase(entry.getKey(), entry.getValue()));
        }
        builder.append("\n");
        for (Map.Entry<String, Class<?>> entry : fieldAndType.entrySet()){
            builder.append(setterCase(entry.getKey(), entry.getValue()));
            builder.append(getterCase(entry.getKey(), entry.getValue()));
        }
        builder.append("}");
        return builder.toString();
    }

    /**
     * 类中的包名字符串
     * @param packageName 完整包名
     * @return 返回包名字符串
     */
    private static String packageCase(String packageName) {
        StringBuilder builder = new StringBuilder();
        builder.append("package ").append(packageName).append(";\n\n");
        return builder.toString();
    }

    /**
     * 类中的属性字符串
     * @param fieldName 字段名
     * @param type 类型
     * @return 返回属性字符串
     */
    private static String fieldCase(String fieldName, Class<?> type) {
        StringBuilder builder = new StringBuilder();
        builder.append("\tpublic ").append(getTypeString(type)).append(" ").append(fieldName).append(";\n");
        return builder.toString();
    }

    /**
     * 类中的set方法字符串
     * @param fieldName 字段名
     * @param type 类型
     * @return 返回set方法字符串
     */
    private static String setterCase(String fieldName, Class<?> type) {
        StringBuilder builder = new StringBuilder();
        builder.append("\tpublic void set").append(titleCase(fieldName))
                .append("(").append(getTypeString(type)).append(" ").append(fieldName).append(") {\n")
                .append("\t\tthis.").append(fieldName).append(" = ").append(fieldName).append(";\n")
                .append("\t}\n");
        return builder.toString();
    }

    /**
     * 类中的get方法字符串
     * @param fieldName 字段名
     * @param type 类型
     * @return 返回get方法字符串
     */
    private static String getterCase(String fieldName, Class<?> type) {
        StringBuilder builder = new StringBuilder();
        builder.append("\tpublic ").append(getTypeString(type)).append(" get").append(titleCase(fieldName))
                .append("() {\n")
                .append("\t\treturn this.").append(fieldName).append(";\n")
                .append("\t}\n");
        return builder.toString();
    }

    /**
     * 获取对应的类型
     * @param type 类型
     * @return 返回对应类型字符串
     */
    private static String getTypeString(Class<?> type) {
        StringBuilder builder = new StringBuilder();
        builder.append(type.getSimpleName());
        return builder.substring(builder.lastIndexOf(".")+1);
    }
}
